/*
 * @Author: your name
 * @Date: 2021-08-16 08:36:35
 * @LastEditTime: 2022-04-04 11:04:13
 * @LastEditors: Please set LastEditors
 * @Description: In User Settings Edit
 * @FilePath: \phone\src\input_method.cpp
 */
#include "input_method.h"
#include "interface.h"
#include "xlog.h"
#include <thread>
#define LINE_DBG_AWTK printf("%s(%d)\n\r", (char*)__FUNCTION__, __LINE__)
InputMethod* InputMethod::instance = nullptr;
InputMethod::InputMethod(std::unique_ptr<Widget>& page)
    : primaryWidget(page)
{
    edit.reset(GuiEngine::GetInstance().NewWidget());
    lastKey = KeyboardValue::KEYBOARD_VALUE_END;
    index = 0;
    chooseRuning = false;
    IMRuning = false;
    cursor = 0;
    showTime = 0;
    ctx = nullptr;
    inputMethod = InputMethodsType::INPUT_METHOD_NUM;
    editLength = 0;
    startIndex = 0;
    maxLength = 63;
    IM_TRTEXT[static_cast<int>(InputMethodsType::INPUT_METHOD_NUM)] = "im_num";
    IM_TRTEXT[static_cast<int>(InputMethodsType::INPUT_METHOD_LOWERCASE)] = "im_lowercase";
    IM_TRTEXT[static_cast<int>(InputMethodsType::INPUT_METHOD_MAJUSCULE)] = "im_majuscule";
    IM_TRTEXT[static_cast<int>(InputMethodsType::INPUT_METHOD_ALL_ABOVE)] = "im_all";
    choose[static_cast<int>(InputMethodsType::INPUT_METHOD_NUM)][KeyboardValue::KEY_NUM_0] = "0";
    choose[static_cast<int>(InputMethodsType::INPUT_METHOD_NUM)][KeyboardValue::KEY_NUM_1] = "1";
    choose[static_cast<int>(InputMethodsType::INPUT_METHOD_NUM)][KeyboardValue::KEY_NUM_2] = "2";
    choose[static_cast<int>(InputMethodsType::INPUT_METHOD_NUM)][KeyboardValue::KEY_NUM_3] = "3";
    choose[static_cast<int>(InputMethodsType::INPUT_METHOD_NUM)][KeyboardValue::KEY_NUM_4] = "4";
    choose[static_cast<int>(InputMethodsType::INPUT_METHOD_NUM)][KeyboardValue::KEY_NUM_5] = "5";
    choose[static_cast<int>(InputMethodsType::INPUT_METHOD_NUM)][KeyboardValue::KEY_NUM_6] = "6";
    choose[static_cast<int>(InputMethodsType::INPUT_METHOD_NUM)][KeyboardValue::KEY_NUM_7] = "7";
    choose[static_cast<int>(InputMethodsType::INPUT_METHOD_NUM)][KeyboardValue::KEY_NUM_8] = "8";
    choose[static_cast<int>(InputMethodsType::INPUT_METHOD_NUM)][KeyboardValue::KEY_NUM_9] = "9";
    choose[static_cast<int>(InputMethodsType::INPUT_METHOD_NUM)][KeyboardValue::KEY_ASTERISK] = "*";
    choose[static_cast<int>(InputMethodsType::INPUT_METHOD_NUM)][KeyboardValue::KEY_POUND_SIGN] = "#";
    choose[static_cast<int>(InputMethodsType::INPUT_METHOD_LOWERCASE)][KeyboardValue::KEY_NUM_0] = " ";
    choose[static_cast<int>(InputMethodsType::INPUT_METHOD_LOWERCASE)][KeyboardValue::KEY_NUM_1] = "";
    choose[static_cast<int>(InputMethodsType::INPUT_METHOD_LOWERCASE)][KeyboardValue::KEY_NUM_2] = "abc2";
    choose[static_cast<int>(InputMethodsType::INPUT_METHOD_LOWERCASE)][KeyboardValue::KEY_NUM_3] = "def3";
    choose[static_cast<int>(InputMethodsType::INPUT_METHOD_LOWERCASE)][KeyboardValue::KEY_NUM_4] = "ghi4";
    choose[static_cast<int>(InputMethodsType::INPUT_METHOD_LOWERCASE)][KeyboardValue::KEY_NUM_5] = "jkl5";
    choose[static_cast<int>(InputMethodsType::INPUT_METHOD_LOWERCASE)][KeyboardValue::KEY_NUM_6] = "mno6";
    choose[static_cast<int>(InputMethodsType::INPUT_METHOD_LOWERCASE)][KeyboardValue::KEY_NUM_7] = "pqrs7";
    choose[static_cast<int>(InputMethodsType::INPUT_METHOD_LOWERCASE)][KeyboardValue::KEY_NUM_8] = "tuv8";
    choose[static_cast<int>(InputMethodsType::INPUT_METHOD_LOWERCASE)][KeyboardValue::KEY_NUM_9] = "wxyz9";
    choose[static_cast<int>(InputMethodsType::INPUT_METHOD_LOWERCASE)][KeyboardValue::KEY_ASTERISK] = ".*,'?!\\-()@/:_;+&%=<>$[]{}~^";
    choose[static_cast<int>(InputMethodsType::INPUT_METHOD_LOWERCASE)][KeyboardValue::KEY_POUND_SIGN] = "#";
    choose[static_cast<int>(InputMethodsType::INPUT_METHOD_MAJUSCULE)][KeyboardValue::KEY_NUM_0] = " ";
    choose[static_cast<int>(InputMethodsType::INPUT_METHOD_MAJUSCULE)][KeyboardValue::KEY_NUM_1] = "";
    choose[static_cast<int>(InputMethodsType::INPUT_METHOD_MAJUSCULE)][KeyboardValue::KEY_NUM_2] = "ABC2";
    choose[static_cast<int>(InputMethodsType::INPUT_METHOD_MAJUSCULE)][KeyboardValue::KEY_NUM_3] = "DEF3";
    choose[static_cast<int>(InputMethodsType::INPUT_METHOD_MAJUSCULE)][KeyboardValue::KEY_NUM_4] = "GHI4";
    choose[static_cast<int>(InputMethodsType::INPUT_METHOD_MAJUSCULE)][KeyboardValue::KEY_NUM_5] = "JKL5";
    choose[static_cast<int>(InputMethodsType::INPUT_METHOD_MAJUSCULE)][KeyboardValue::KEY_NUM_6] = "MNO6";
    choose[static_cast<int>(InputMethodsType::INPUT_METHOD_MAJUSCULE)][KeyboardValue::KEY_NUM_7] = "PQRS7";
    choose[static_cast<int>(InputMethodsType::INPUT_METHOD_MAJUSCULE)][KeyboardValue::KEY_NUM_8] = "TUV8";
    choose[static_cast<int>(InputMethodsType::INPUT_METHOD_MAJUSCULE)][KeyboardValue::KEY_NUM_9] = "WXYZ9";
    choose[static_cast<int>(InputMethodsType::INPUT_METHOD_MAJUSCULE)][KeyboardValue::KEY_ASTERISK] = ".*,'?!\\-()@/:_;+&%=<>$[]{}~^";
    choose[static_cast<int>(InputMethodsType::INPUT_METHOD_MAJUSCULE)][KeyboardValue::KEY_POUND_SIGN] = "#";
    choose[static_cast<int>(InputMethodsType::INPUT_METHOD_ALL_ABOVE)][KeyboardValue::KEY_NUM_0] = "0";
    choose[static_cast<int>(InputMethodsType::INPUT_METHOD_ALL_ABOVE)][KeyboardValue::KEY_NUM_1] = "1";
    choose[static_cast<int>(InputMethodsType::INPUT_METHOD_ALL_ABOVE)][KeyboardValue::KEY_NUM_2] = "2aAbBcC";
    choose[static_cast<int>(InputMethodsType::INPUT_METHOD_ALL_ABOVE)][KeyboardValue::KEY_NUM_3] = "3dDeEfF";
    choose[static_cast<int>(InputMethodsType::INPUT_METHOD_ALL_ABOVE)][KeyboardValue::KEY_NUM_4] = "4gGhHiI";
    choose[static_cast<int>(InputMethodsType::INPUT_METHOD_ALL_ABOVE)][KeyboardValue::KEY_NUM_5] = "5jJkKlL";
    choose[static_cast<int>(InputMethodsType::INPUT_METHOD_ALL_ABOVE)][KeyboardValue::KEY_NUM_6] = "6mMnNoO";
    choose[static_cast<int>(InputMethodsType::INPUT_METHOD_ALL_ABOVE)][KeyboardValue::KEY_NUM_7] = "7pPqQrRsS";
    choose[static_cast<int>(InputMethodsType::INPUT_METHOD_ALL_ABOVE)][KeyboardValue::KEY_NUM_8] = "8tTuUvV";
    choose[static_cast<int>(InputMethodsType::INPUT_METHOD_ALL_ABOVE)][KeyboardValue::KEY_NUM_9] = "9wWxXyYzZ";
    choose[static_cast<int>(InputMethodsType::INPUT_METHOD_ALL_ABOVE)][KeyboardValue::KEY_ASTERISK] = ".*,'?!\\-()@/:_;+&%=<>$[]{}~^";
    choose[static_cast<int>(InputMethodsType::INPUT_METHOD_ALL_ABOVE)][KeyboardValue::KEY_POUND_SIGN] = "#";
}
InputMethod::~InputMethod()
{
    if (chooseRuning || IMRuning) {
        showTime = STOP_SHOW_TIME;
    }
    /**
     * @brief
     * 下面屏蔽的代码是用于保证线程正常退出再完成析构函数，不要删掉。
     */
    while (chooseRuning || IMRuning) {
        std::this_thread::sleep_for(std::chrono::milliseconds(50));
    }
    std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
void InputMethod::Init()
{
    if (!primaryWidget.get() || !primaryWidget->IsValid()) {
        LOG_E("check if the primary page is opened.\n");
        return;
    }
    /**
     * @brief
     * 主窗口显示当前输入法
     */
    std::unique_ptr<Widget> view(GuiEngine::GetInstance().NewWidget());
    if (GuiEngine::GetInstance().Lookup(primaryWidget.get(), "button2", true, view.get())) {
        GuiEngine::GetInstance().SetTrText(view.get(), IM_TRTEXT[static_cast<int>(inputMethod)].c_str());
    } else {
        LOG_E("can't find the input method lable.\n");
    }
}
void InputMethod::InputOperation(void* ctx)
{
    KeyboardValue key = KeyboardValue::KEYBOARD_VALUE_END;
    IS_VALID_PTR(ctx)
    Context* p = (Context*)ctx;
    p->GetData(key);
    // std::thread t(&InputMethod::ChooseShow, this, key);
    // t.detach(); //设置线程分离属性，线程结束后自动释放资源
    InputOperation(key);
}
void InputMethod::InputOperation(KeyboardValue key)
{
    std::thread t(&InputMethod::ChooseShow, this, key);
    t.detach(); //设置线程分离属性，线程结束后自动释放资源
}
void InputMethod::ChooseShow(KeyboardValue key)
{
    /**
     * @brief
     * 输入法选择销毁。
     */
    ChooseShowStop("imchoose");
    auto funCallback = [](void* ctx) {
        IS_VALID_PTR(ctx)
        ContextV2<KeyboardValue>* p = (ContextV2<KeyboardValue>*)ctx;
        KeyboardValue key = p->data;
        delete p;
        InputMethod* im = dynamic_cast<InputMethod*>(InputMethod::GetInstance());
        IS_VALID_PTR(im)
        im->ChooseShowIQ(key);
    };
    /**
     * @brief
     * 用锁来控制流程时序，保证每次刷新的候选字符都能显示一个周期
     */
    m_mutex.lock();
    if (!EditRefresh(key)) {
        m_mutex.unlock();
        return;
    }
    int keylen = GetChooseLength(key);
    printf("keylen=%d\n\r", keylen);
    if (keylen <= 1) {
        LOG_I("There is no candidate character.\n");
        chooseRuning = false;
        /**
         * @brief
         * 触发可选字符消失事件。
         */
        InputFinshedEventIQ();
        m_mutex.unlock();
        return;
    }
    showTime = 0;
    /**
     * @brief
     * 如果候选字符大于1个，则显示候选字符。
     */
    CommonFunc::GetInstance().GuiIdleQueueWithData(funCallback, key);
    if (chooseRuning) {
        m_mutex.unlock();
        return;
    }
    chooseRuning = true;
    m_mutex.unlock();
    const unsigned int SLEEP_TIME = 50;
    while (1) {
        std::this_thread::sleep_for(std::chrono::milliseconds(SLEEP_TIME));
        showTime += SLEEP_TIME;
        if (showTime >= STOP_SHOW_TIME || !chooseRuning) {
            m_mutex.lock();
            break;
        }
    }
    ChooseShowStop("choose");
    chooseRuning = false;
    lastKey = KeyboardValue::KEYBOARD_VALUE_END;
    m_mutex.unlock();
}
void InputMethod::ChooseShowStop(std::string target)
{
    auto funCallback2 = [](void* ctx) {
        IS_VALID_PTR(ctx)
        ContextV2<std::string>* p = (ContextV2<std::string>*)ctx;
        std::string target = p->data;
        delete p;
        InputMethod* im = dynamic_cast<InputMethod*>(InputMethod::GetInstance());
        IS_VALID_PTR(im)
        im->ChooseShowStopIQ(target);
    };
    CommonFunc::GetInstance().GuiIdleQueueWithData(funCallback2, target);
    // ChooseShowStopIQ(target);
}
void InputMethod::ChooseShowStopIQ(std::string target)
{
    std::unique_ptr<Widget> view(GuiEngine::GetInstance().NewWidget());
    if (!GuiEngine::GetInstance().Lookup(primaryWidget.get(), target.c_str(), true, view.get())) {
        LOG_E("can't find target to stop show.\n");
        return;
    }
    std::unique_ptr<Widget> view2(GuiEngine::GetInstance().NewWidget());
    if (GuiEngine::GetInstance().Lookup(view.get(), "iMItemView", true, view2.get())) {
        GuiEngine::GetInstance().Destroy(view2.get());
        if ("choose" == target) {
            InputFinshedEvent();
        }
    }
}
bool InputMethod::EditRefresh(KeyboardValue key)
{
    LINE_DBG_AWTK;
    if (chooseRuning && key == lastKey) {
        editValue.erase(cursor - 1, 1);
        cursor--;
    }
    LINE_DBG_AWTK;
    if (maxLength != 0 && maxLength <= editValue.length()) {
        /**
         * @brief
         * 输入字符已经超出长度
         */
        return false;
    }
    LINE_DBG_AWTK;
    if (key != lastKey) {
        LINE_DBG_AWTK;
        index = GetChooseLength(key);
        ChooseShowStop("choose");
    }
    unsigned int nextIndex = NextIndex(key);
    std::string strtmp = GetOneChooseCharacter(nextIndex, key);
    // printf("---->%s, strtmp.size()=%d\n", __FUNCTION__, strtmp.size());
    if (strtmp.size() > 0) {
        editValue.insert(cursor, strtmp); // editValue.insert(cursor, GetOneChooseCharacter(nextIndex, key));
        cursor++;
        if (cursor > startIndex + editLength) {
            startIndex = cursor - editLength;
        }
        LINE_DBG_AWTK;
        EditShowValue();
        LINE_DBG_AWTK;
    }

    lastKey = key;
    return true;
}
void InputMethod::EditShowValue()
{
    LINE_DBG_AWTK;
    if (editValue.length() == 0) {
        SetEditText(edit.get(), "", nullptr);
        ShowCursor();
        return;
    }
    LINE_DBG_AWTK;
    auto funCallback = [](void* ctx) {
        IS_VALID_PTR(ctx)
        ContextV2<std::string>* p = (ContextV2<std::string>*)ctx;
        std::string value = p->data;
        delete p;
        InputMethod* im = dynamic_cast<InputMethod*>(InputMethod::GetInstance());
        IS_VALID_PTR(im)
        LINE_DBG_AWTK;
        im->EditRefreshIQ(value);
        
        LINE_DBG_AWTK;
    };
    LINE_DBG_AWTK;
    // if (editValue.length() > 0)
    //     printf("editValue len=%d,%s\n\r", editValue.length(), editValue.c_str());
    CommonFunc::GetInstance().GuiIdleQueueWithData(funCallback, editValue);
}
void InputMethod::EditRefreshIQ(std::string value)
{
    LOG_I("edit value = %s.\n", value.c_str());
    if (!edit.get() || !edit->IsValid()) {
        return;
    }
    MoveCursorIQ();
    InputFinshedEvent();
}
void InputMethod::ChooseShowIQ(KeyboardValue key)
{
    if (!SwitchSelectedItem(key)) {
        /**
         * @brief
         * 如果没有找到下一个item，先创建下一页item
         */
        CreateChooseView(key);
        SwitchSelectedItem(key);
    }
}
bool InputMethod::SwitchSelectedItem(KeyboardValue key)
{
    std::unique_ptr<Widget> chooseView(GuiEngine::GetInstance().NewWidget());
    if (!GuiEngine::GetInstance().Lookup(primaryWidget.get(), "choose", true, chooseView.get())) {
        LOG_E("can't look up choose view, check the xml file please.\n");
        return false;
    }
    char itemName[16] = { 0 };
    unsigned int lastIndex = index;
    unsigned int currentIndex = NextIndex(key);
    std::unique_ptr<Widget> view(GuiEngine::GetInstance().NewWidget());
    snprintf(itemName, 16, "item%d", currentIndex);
    if (GuiEngine::GetInstance().Lookup(chooseView.get(), itemName, true, view.get())) {
        /**
         * @brief
         * 如果显示的所有item里面找到选择的下一个item，直接修改item属性进行选定
         */
        GuiEngine::GetInstance().UseStyle(view.get(), "itemFocus");
        std::unique_ptr<Widget> view2(GuiEngine::GetInstance().NewWidget());
        itemName[0] = 0;
        snprintf(itemName, 16, "item%d", lastIndex);
        if (GuiEngine::GetInstance().Lookup(chooseView.get(), itemName, true, view2.get())) {
            GuiEngine::GetInstance().UseStyle(view2.get(), "item");
        }
        index = currentIndex;
        return true;
    } else {
        return false;
    }
}
void InputMethod::CreateChooseView(KeyboardValue key)
{
    /**
     * @brief
     * 单次显示候选字符数
     */
    const unsigned int ITEM_TOTAL = 5;
    unsigned int create = index;
    std::unique_ptr<Widget> chooseView(GuiEngine::GetInstance().NewWidget());
    if (!GuiEngine::GetInstance().Lookup(primaryWidget.get(), "choose", true, chooseView.get())) {
        LOG_E("can't look up choose view, check the xml file please.\n");
        return;
    }
    create++;
    if (create >= GetChooseLength(key)) {
        create = 0;
    }
    /**
     * @brief
     * 一次性销毁所有的item:destroy名称为"iMItemView"的view控件
     */
    std::unique_ptr<Widget> view(GuiEngine::GetInstance().NewWidget());
    if (GuiEngine::GetInstance().Lookup(chooseView.get(), "iMItemView", true, view.get())) {
        GuiEngine::GetInstance().Destroy(view.get());
    }
    std::unique_ptr<Widget> view2(GuiEngine::GetInstance().NewWidget());
    if (GuiEngine::GetInstance().ViewCreate(chooseView.get(), 0, 0, 0, 0, view2.get())) {
        SetItemView(view2.get());
        for (unsigned int i = 0; i < ITEM_TOTAL; i++) {
            if (CreateItemView(chooseView.get(), view2.get())) {
                GuiEngine::GetInstance().UseStyle(view2.get(), "ITEM");
                CreateOneItem(view2.get(), create, key);
            }
            if (create == GetChooseLength(key) - 1) {
                break;
            }
            create++;
            if (create >= GetChooseLength(key)) {
                create = 0;
            }
        }
    }
}
void InputMethod::SetItemView(Widget* view)
{
    GuiEngine::GetInstance().SetName(view, "iMItemView");
    GuiEngine::GetInstance().SetSelfLayout(view, "default(x=0,y=0,w=100%,h=100%)");
    /**
     * @brief
     * 设置项view控件有1行、1列，设置项按数量居中排列
     */
    GuiEngine::GetInstance().SetChildrenLayout(view, "default(r=1,c=0,align_h=center,x=0,y=0,s=0)");
}
bool InputMethod::CreateItemView(Widget* target, Widget* view2)
{
    std::unique_ptr<Widget> view(GuiEngine::GetInstance().NewWidget());
    if (GuiEngine::GetInstance().Lookup(target, "iMItemView", true, view.get())) {
        if (GuiEngine::GetInstance().ViewCreate(view.get(), 0, 0, 0, 0, view2)) {
            /**
             * @brief
             * 设置每个字符宽度
             */
            GuiEngine::GetInstance().SetSelfLayout(view2, "default(w=42,h=100%)");
            /**
             * @brief
             * 每个设置项有1列、1行
             */
            GuiEngine::GetInstance().SetChildrenLayout(view2, "default(c=1,r=1)");
            return true;
        }
    }
    LOG_E("create view failed\n");
    return false;
}
void InputMethod::CreateOneItem(Widget* view2, int iTarget, KeyboardValue key)
{
    std::unique_ptr<Widget> view3(GuiEngine::GetInstance().NewWidget());
    if (GuiEngine::GetInstance().LabelCreate(view2, 0, 0, 0, 0, view3.get())) {
        char name[16] = { 0 };
        snprintf(name, 16, "item%d", iTarget);
        GuiEngine::GetInstance().SetName(view3.get(), name);
        GuiEngine::GetInstance().UseStyle(view3.get(), "item");
        GuiEngine::GetInstance().SetTextUtf8(view3.get(), GetOneChooseCharacter(iTarget, key).c_str());
    }
}
std::string InputMethod::GetOneChooseCharacter(unsigned int target, KeyboardValue key)
{
    std::map<KeyboardValue, std::string>::iterator iter;
    iter = choose[static_cast<int>(inputMethod)].find(key);
    if (iter != choose[static_cast<int>(inputMethod)].end()) {
        if (target >= choose[static_cast<int>(inputMethod)][key].length()) {
            LOG_E("no choose character is found.\n");
            return ""; //"error";
        }
        return choose[static_cast<int>(inputMethod)][key].substr(target, 1);
    } else {
        LOG_E("something wrong happen\n");
        return ""; //"error";
    }
}
unsigned int InputMethod::GetChooseLength(KeyboardValue key)
{
    std::map<KeyboardValue, std::string>::iterator iter;
    iter = choose[static_cast<int>(inputMethod)].find(key);
    if (iter != choose[static_cast<int>(inputMethod)].end()) {
        return choose[static_cast<int>(inputMethod)][key].length();
    } else {
        return 0;
    }
}
void InputMethod::MoveCursor(void* ctx)
{
    Context* p = (Context*)ctx;
    KeyboardValue key = KeyboardValue::KEYBOARD_VALUE_END;
    p->GetData(key);
    if (key == KeyboardValue::KEY_DIRECTION_LEFT && cursor > 0) {
        cursor--;
        /**
         * @brief
         * 左移的时候，左边留一位预览。
         */
        if (startIndex + 1 > cursor && startIndex > 0) {
            startIndex--;
        }
    } else if (key == KeyboardValue::KEY_DIRECTION_RIGHT && cursor < editValue.length()) {
        cursor++;
        /**
         * @brief
         * 右移的时候，右边留一位预览。
         */
        if (startIndex + editLength - 1 < cursor) {
            startIndex++;
        }
    } else {
        LOG_E("invalid key\n");
        return;
    }
    MoveCursorIQ();
}
void InputMethod::MoveCursorIQ()
{
    SetEditText(edit.get(), editValue, ctx);
    ShowCursor();
    // std::unique_ptr<Widget> view(GuiEngine::GetInstance().NewWidget());
    // if (GuiEngine::GetInstance().Lookup(edit.get(), "cursor", true, view.get()))
    // {
    //     GuiEngine::GetInstance().Destroy(view.get());
    // }
    // if (GuiEngine::GetInstance().Lookup(edit.get(), EDIT_VALUE, true, view.get()))
    // {
    //     std::unique_ptr<Widget> view3(GuiEngine::GetInstance().NewWidget());
    //     if (GuiEngine::GetInstance().LabelCreate(view.get(), 0, 0, 0, 0, view3.get()))
    //     {
    //         // char text[1024];
    //         char text[1024] = {0};
    //         snprintf(text, 1024, "default(x=%d,y=m,w=1,h=22)", (cursor - startIndex) * cursorWidth - 1);
    //         GuiEngine::GetInstance().SetSelfLayout(view3.get(), text);
    //         GuiEngine::GetInstance().SetName(view3.get(), "cursor");
    //         GuiEngine::GetInstance().UseStyle(view3.get(), "cursor");
    //         GuiEngine::GetInstance().SetFloating(view3.get(), true);
    //         text[0] = 0;
    //         snprintf(text, 1024, "opacity(from=255, to=0, yoyo_times=0, duration=600, delay=600)");
    //         GuiEngine::GetInstance().CreateAnimator(view3.get(), text);
    //     }
    // }
}
void InputMethod::Delete(void* ctx)
{
    if (cursor > 0) {
        editValue.erase(cursor - 1, 1);
        cursor--;
    }
    /**
     * @brief
     * 左移的时候，左边留一位预览。
     */
    if (startIndex + 1 > cursor && startIndex > 0) {
        startIndex--;
    }
    EditShowValue();
}
void InputMethod::InputMethodChange()
{
    InputMethodsType lastInputMethod = inputMethod;
    // CommonFunc::GetInstance().FunctionSelection(inputMethod, KeyboardValue::KEY_DIRECTION_RIGHT);
    InputMethodSelection(inputMethod, lastInputMethod);
    /**
     * @brief Construct a new if object
     * 只支持单个输入法时，上一个输入法永远被赋值为非法值FUNCTION_END，此时不需要切换。
     */
    if (lastInputMethod == InputMethodsType::FUNCTION_END) {
        return;
    }
    Init();
    std::thread t(&InputMethod::ChooseInputMethod, this, lastInputMethod);
    t.detach(); //设置线程分离属性，线程结束后自动释放资源
}
void InputMethod::ChooseInputMethod(InputMethodsType method)
{
    ChooseShowStop("choose");
    auto funCallback = [](void* ctx) {
        IS_VALID_PTR(ctx)
        ContextV2<InputMethodsType>* p = (ContextV2<InputMethodsType>*)ctx;
        InputMethodsType method = p->data;
        delete p;
        InputMethod* im = dynamic_cast<InputMethod*>(InputMethod::GetInstance());
        IS_VALID_PTR(im)
        im->ChooseInputMethodIQ(method);
    };
    /**
     * @brief
     * 用锁来控制流程时序，保证每次刷新的候选字符都能显示一个周期
     */
    m_mutex.lock();
    showTime = 0;
    CommonFunc::GetInstance().GuiIdleQueueWithData(funCallback, method);
    if (IMRuning) {
        m_mutex.unlock();
        return;
    }
    IMRuning = true;
    m_mutex.unlock();
    const unsigned int SLEEP_TIME = 50;
    while (1) {
        std::this_thread::sleep_for(std::chrono::milliseconds(SLEEP_TIME));
        showTime += SLEEP_TIME;
        if (showTime >= STOP_SHOW_TIME || !IMRuning) {
            m_mutex.lock();
            break;
        }
    }
    ChooseShowStop("imchoose");
    IMRuning = false;
    m_mutex.unlock();
}
void InputMethod::ChooseInputMethodIQ(InputMethodsType method)
{
    if (!SwitchSelectedItem(method)) {
        /**
         * @brief
         * 如果没有找到下一个item，先创建下一页item
         */
        CreateChooseView(method);
        SwitchSelectedItem(method);
    }
}
bool InputMethod::SwitchSelectedItem(InputMethodsType method)
{
    std::unique_ptr<Widget> view(GuiEngine::GetInstance().NewWidget());
    if (!GuiEngine::GetInstance().Lookup(primaryWidget.get(), "imchoose", true, view.get())) {
        return false;
    }
    InputMethodsType lastMethod = InputMethodsType::FUNCTION_END;
    // CommonFunc::GetInstance().FunctionSelection(method, KeyboardValue::KEY_DIRECTION_RIGHT);
    InputMethodSelection(method, lastMethod);
    return CommonFunc::GetInstance().SwitchSelectedItem(view.get(), static_cast<int>(method), static_cast<int>(lastMethod));
}
void InputMethod::CreateChooseView(InputMethodsType method)
{
    /**
     * @brief
     * 单次显示输入法的个数
     */
    const unsigned int ITEM_TOTAL = 4;
    method = InputMethodsType::INPUT_METHOD_NUM;
    unsigned int create = static_cast<int>(method);
    /**
     * @brief
     * 一次性销毁所有的item:destroy名称为"imchooseView"的view控件
     */
    std::unique_ptr<Widget> view(GuiEngine::GetInstance().NewWidget());
    if (GuiEngine::GetInstance().Lookup(primaryWidget.get(), "imchoose", true, view.get())) {
        std::unique_ptr<Widget> view2(GuiEngine::GetInstance().NewWidget());
        if (GuiEngine::GetInstance().Lookup(view.get(), "iMItemView", true, view2.get())) {
            GuiEngine::GetInstance().Destroy(view2.get());
        }
        if (GuiEngine::GetInstance().ViewCreate(view.get(), 0, 0, 0, 0, view2.get())) {
            SetItemView(view2.get());
            for (unsigned int i = 0; i < ITEM_TOTAL; i++) {
                create = static_cast<int>(method);
                if (CreateItemView(view.get(), view2.get())) {
                    GuiEngine::GetInstance().UseStyle(view2.get(), "imchoose");
                    CreateOneItem(view2.get(), create, method);
                }
                if (create == static_cast<int>(InputMethodsType::FUNCTION_END) - 1) {
                    break;
                }
                CommonFunc::GetInstance().FunctionSelection(method, KeyboardValue::KEY_DIRECTION_RIGHT);
            }
        }
    } else {
        LOG_E("can't create input method choosing view, check the xml files.\n");
    }
}
void InputMethod::CreateOneItem(Widget* view2, int iTarget, InputMethodsType method)
{
    std::unique_ptr<Widget> view3(GuiEngine::GetInstance().NewWidget());
    if (GuiEngine::GetInstance().LabelCreate(view2, 0, 0, 0, 0, view3.get())) {
        char name[16] = { 0 };
        snprintf(name, 16, "item%d", iTarget);
        GuiEngine::GetInstance().SetName(view3.get(), name);
        GuiEngine::GetInstance().UseStyle(view3.get(), "item");
        GuiEngine::GetInstance().SetTrText(view3.get(), IM_TRTEXT[static_cast<int>(method)].c_str());
    }
}
void InputMethod::InputFinshedEventIQ()
{
    Context *p = new Context;
    auto funCallback = [](void *ctx)
    {
        IS_VALID_PTR(ctx)
        Context *p2 = (Context *)ctx;
        delete p2;
        InputMethod* im = dynamic_cast<InputMethod*>(InputMethod::GetInstance());
        IS_VALID_PTR(im)
        im->InputFinshedEvent();
    };
    p->eventCallback = funCallback;
    if (!GuiEngine::GetInstance().IdleQueue(p))
    {
        LOG_W("IdleQueue_V2 falied\n");
        delete p;
    }
}
void InputMethod::SetEdit(Widget* edit, unsigned int cursorWidth, void* ctx, unsigned int editLength, std::string editValue)
{
    InputMethod::edit->SetWidget(edit);
    InputMethod::cursorWidth = cursorWidth;
    InputMethod::ctx = ctx;
    InputMethod::editLength = editLength;
    InputMethod::editValue = editValue;
    cursor = InputMethod::editValue.length();
    if (cursor > startIndex + editLength) {
        startIndex = cursor - editLength;
    }
}
unsigned int InputMethod::NextIndex(KeyboardValue key)
{
    unsigned int nextIndex = index + 1;
    if (nextIndex >= GetChooseLength(key)) {
        nextIndex = 0;
    }
    return nextIndex;
}
void InputMethod::SetInputMethodType(InputMethodsType type)
{
    inputMethod = type;
    Init();
}
void InputMethod::ShowCursor()
{
    // SetEditText(edit.get(), "", nullptr);
    std::unique_ptr<Widget> view(GuiEngine::GetInstance().NewWidget());
    if (GuiEngine::GetInstance().Lookup(edit.get(), "cursor", true, view.get())) {
        GuiEngine::GetInstance().Destroy(view.get());
    }
    if (GuiEngine::GetInstance().Lookup(edit.get(), EDIT_VALUE, true, view.get())) {
        std::unique_ptr<Widget> view3(GuiEngine::GetInstance().NewWidget());
        if (GuiEngine::GetInstance().LabelCreate(view.get(), 0, 0, 0, 0, view3.get())) {
            // char text[1024];
            char text[1024] = { 0 };
            int cursorX = ((cursor - startIndex) * cursorWidth - 1) <= 0 ? 0 : ((cursor - startIndex) * cursorWidth - 1);
            snprintf(text, 1024, "default(x=%d,y=m,w=1,h=22)", cursorX);
            GuiEngine::GetInstance().SetSelfLayout(view3.get(), text);
            GuiEngine::GetInstance().SetName(view3.get(), "cursor");
            GuiEngine::GetInstance().UseStyle(view3.get(), "cursor");
            GuiEngine::GetInstance().SetFloating(view3.get(), true);
            text[0] = 0;
            snprintf(text, 1024, "opacity(from=255, to=0, yoyo_times=0, duration=600, delay=600)");
            GuiEngine::GetInstance().CreateAnimator(view3.get(), text);
        }
    }
}
bool& InputMethod::GetChoosing()
{
    return chooseRuning;
}
